#include "smartconfig.h"
#include <Arduino.h>
smartConfig_ &smartConfig = smartConfig.getInstance();

/**
 * @brief 获取 SSID
 *
 * @return String WIFI SSID
 */
String smartConfig_::getSSID()
{
    return String(config.stassid);
}

/**
 * @brief 获取密码
 *
 * @return String 密码
 */
String smartConfig_::getPassword()
{
    return String(config.stapsw);
}

/**
 * @brief 判断是否需要进入恢复出厂设置
 *
 * @return true 需要
 * @return false 不需要
 */
bool smartConfig_::checkNetConfigNeeded()
{
    return factoryResetPending;
}

/**
 * @brief 延时重启函数
 *
 * @param t 重启延时时间
 */
void smartConfig_::delayRestart(float t)
{
    delayTimer.attach(t, []()
                      { ESP.restart(); });
}

/**
 * @brief 设置 SmartConfig
 *
 * @details 用于向服务器发送设备的 MAC 地址以进行配网设置
 */
void smartConfig_::setConfig()
{
    String mac = WiFi.macAddress().substring(8); // 取 mac 地址做主题用
    mac.replace(":", "");                        // 去掉：号
    WiFiClient client_bemfa_WiFiClient;
    HTTPClient http_bemfa_HTTPClient;
    http_bemfa_HTTPClient.begin(client_bemfa_WiFiClient, "http://pro.bemfa.com/vv/setSmartConfig?version=1&user=" + mac);
    int httpCode = http_bemfa_HTTPClient.GET();
    if (httpCode == 200)
    {
        Serial.println("wifi smartconfig ok");
    }
    http_bemfa_HTTPClient.end();
}

/**
 * @brief 恢复出厂设置，清除存储的 WiFi 信息
 */
void smartConfig_::restoreFactory()
{
    Serial.println("Restore Factory....... ");
    config.magic = 0x00;
    strcpy(config.stassid, "");
    strcpy(config.stapsw, "");
    config.magic = 0x00;
    saveConfigToPreferences();
    delayRestart(1);
    while (1)
    {
        delay(100);
    }
}

/**
 * @brief 初始化 WiFi 信息，并连接路由器网络
 */
void smartConfig_::initWiFi()
{
    char temp[32];
    uint8_t mac[6];
    WiFi.macAddress(mac);
    sprintf(temp, "%s_%02X%02X%02X", "bemfa", mac[3], mac[4], mac[5]);
    WiFi.hostname(temp);
    if (WiFi.status() != WL_CONNECTED)
    {
        WiFi.disconnect();
        WiFi.mode(WIFI_STA);
        WiFi.begin(config.stassid, config.stapsw);
    }
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(200);
        Serial.print(".");
    }
    Serial.println(" ");
    if (configFlag == 1)
    {
        setConfig();
    }
    Serial.println("WiFi config OK");
    WiFi.softAP(temp);
}

/**
 * @brief 开始进行 SmartConfig 配网
 */
void smartConfig_::startWiFiConfig()
{
    if (configFlag == 1)
    {
        Serial.println(" Smartconfig begin,Waiting for WeChat Config.....");
        WiFi.mode(WIFI_STA);
        WiFi.stopSmartConfig();
        WiFi.beginSmartConfig();
        int cnt = 0;
        bool flag_ok = false;
        while (!WiFi.smartConfigDone())
        {
            delay(300);
            if (flag_ok == true)
                continue;
            if (WiFi.smartConfigDone())
            {
                strcpy(config.stassid, WiFi.SSID().c_str());
                strcpy(config.stapsw, WiFi.psk().c_str());
                config.magic = 0xAA;
                saveConfigToPreferences();
                flag_ok = true;
            }
            cnt++;
            if (cnt >= 600)
            {
                delayRestart(0);
            }
        }
    }
}

/**
 * @brief 加载存储的信息，并检查是否进行了反复 5 次重启恢复出厂信息
 *
 * @details 一开始加载会首先读取内存中的重启次数，并且 +1，然后判断是否达到 5 次，以便判断是否需要恢复工厂模式。
 */
void smartConfig_::loadConfig()
{
    // 获取设备的 MAC 地址
    uint8_t mac[6];
    WiFi.macAddress(mac);

    // 将配置信息读取到结构体 config 中
    loadConfigFromPreferences();

    // 增加设备重启次数并检查是否需要恢复出厂设置
    config.reboot++;
    // 打印重启次数
    Serial.println("Press [ " + String(RESTARTCOUNT - config.reboot) +
                   " ] consecutively to restart!");
    if (config.reboot >= RESTARTCOUNT)
    {
        config.reboot = 0;
        factoryResetPending = true; // 需要重新配网
        restoreFactory();           // 执行恢复出厂设置操作
    }

    // 检查魔数是否匹配，检查从 nvs 中读取回来的数据是否错误，正确返回应该是 0XAA
    if (config.magic != magicNumber)
    {
        configFlag = 1;
        factoryResetPending = true; // 需要重新配网
        return;
    }

    // config 已经 + 1。要将修改后的配置信息写回 nvs
    saveConfigToPreferences();

    delay(2000); // 等待 2s 后没有重启，表示不需要恢复出厂设置，可以归零重启次数，并存储 nvs 中
    config.reboot = 0;
    saveConfigToPreferences();
    factoryResetPending = false; // 连续重启时间超过 2s 不需要重新配网
}

/**
 * @brief 保存配置信息到 Preferences 中
 *
 */
void smartConfig_::saveConfigToPreferences()
{
    Preferences preferences;
    if (!preferences.begin("MyConfig", false))
    {
        Serial.println("Failed to open preferences");
        return;
    }

    // 保存每个字段
    preferences.putString("stassid", config.stassid);
    preferences.putString("stapsw", config.stapsw);
    preferences.putString("cuid", config.cuid);
    preferences.putString("ctopic", config.ctopic);
    preferences.putUChar("reboot", config.reboot);
    preferences.putUChar("magic", config.magic);

    preferences.end();
}

/**
 * @brief 从 Preferences 中加载配置信息
 *
 */
void smartConfig_::loadConfigFromPreferences()
{
    Preferences preferences;

    // 尝试打开或创建名为 "MyConfig" 的配置命名空间，若打开失败（即找不到此命名空间或初始化失败），则输出错误信息，并准备使用默认配置
    if (!preferences.begin("MyConfig", false))
    {
        Serial.println("Failed to open preferences or config not found, using default values");
        // 可在此处初始化默认配置
        return;
    }

    // 读取每个字段
    preferences.getString("stassid", config.stassid, sizeof(config.stassid));
    preferences.getString("stapsw", config.stapsw, sizeof(config.stapsw));
    preferences.getString("cuid", config.cuid, sizeof(config.cuid));
    preferences.getString("ctopic", config.ctopic, sizeof(config.ctopic));
    config.reboot = preferences.getUChar("reboot", 0);
    config.magic = preferences.getUChar("magic", 0);

    preferences.end();
}